package edu.iscas.xcheck.analysis.dom.checker;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import edu.iscas.xcheck.analysis.dom.layout.AGDiff;
import edu.iscas.xcheck.analysis.dom.layout.AGNode;
import edu.iscas.xcheck.analysis.dom.layout.AlignmentGraph;
import edu.iscas.xcheck.analysis.dom.matcher.MatchResult;
import edu.iscas.xcheck.analysis.dom.matcher.Matcher;
import edu.iscas.xcheck.analysis.dom.model.BrowserEvent;
import edu.iscas.xcheck.analysis.dom.model.BrowserPage;
import edu.iscas.xcheck.analysis.dom.model.DomNode;
import edu.iscas.xcheck.analysis.dom.model.LocalPage;
import edu.iscas.xcheck.analysis.dom.model.MutationEvent;
import edu.iscas.xcheck.analysis.dom.utils.LayoutUtils;
import edu.iscas.xcheck.analysis.model.StateIssue;
import edu.iscas.xcheck.analysis.model.XbiIssue;
import edu.iscas.xcheck.analysis.model.XbiIssue.ISSUETYPE;
import edu.iscas.xcheck.analysis.model.XbiIssue.XBITYPE;

/**
 * check same sequence page in different browser
 * 
 * @author hmm
 * 
 */
public class PageChecker {

	private Map<String, String> allMatchedNode;
	private XBIResult results;
	private BrowserPage browserPage1;
	private BrowserPage browserPage2;

	private Map<String, DomNode> idMap1;
	private Map<String, DomNode> idMap2;

	private String page;
	private String stateKey;

	private boolean isTest = false;

	public PageChecker(BrowserPage browserPage1, BrowserPage browserPage2,
			XBIResult results) {
		this.browserPage1 = browserPage1;
		this.browserPage2 = browserPage2;
		this.results = results;
		this.page = "page_" + browserPage1.getSeq();
		this.stateKey = String.format("%s_%s", browserPage1.getHash(),
				browserPage2.getHash());
		this.allMatchedNode = new HashMap<>();
		allMatchedNode.put("-1", "-1");
	}

	public void doCheck() {
		List<BrowserEvent> browserEventList1 = browserPage1.getLog()
				.getEvents();
		List<BrowserEvent> browserEventList2 = browserPage2.getLog()
				.getEvents();

		List<String> behaviorIssues = new ArrayList<String>();
		if (browserEventList1 != null && browserEventList2 != null) {
			checkAllEvent(browserEventList1, browserEventList2);
		} else {
			if (browserEventList1 == null) {
				addIssue(XBITYPE.Behavior, ISSUETYPE.Additional, page
						+ "_NOEVENT_1", browserEventList1, browserEventList2);
				behaviorIssues.add(page + "_NOEVENT_1");
			}
			if (browserEventList2 == null) {
				addIssue(XBITYPE.Behavior, ISSUETYPE.Missing, page
						+ "_NOEVENT_2", browserEventList1, browserEventList2);
				behaviorIssues.add(page + "_NOEVENT_2");
			}
		}
	}

	/**
	 * @param browserEventList1
	 * @param browserEventList2
	 */
	private void checkAllEvent(List<BrowserEvent> browserEventList1,
			List<BrowserEvent> browserEventList2) {
		List<String> behaviorIssues = new ArrayList<String>();
		int i = 0;
		for (; i < browserEventList1.size() && i < browserEventList2.size(); i++) {
			double startTime = new Date().getTime();
			BrowserEvent browserEvent1 = browserEventList1.get(i);
			BrowserEvent browserEvent2 = browserEventList2.get(i);

			if (equalEvent(browserEvent1, browserEvent2)) {
				if (browserEvent1.getMutation() == null
						&& browserEvent2.getMutation() == null ) {
					continue;
				}
				if(!equalEventByState(browserEvent1, browserEvent2)) continue;
				if (browserEvent1.getMutation() == null) {
					// ignore the last event
					if (i == browserEventList1.size() - 1
							&& i == browserEventList2.size() - 1)
						continue;
					String issueMsg = formatIssuseString("MISS_MUTATION_1",
							page + "_Event_" + i,
							eventMsgFormat(browserEvent1),
							eventMsgFormat(browserEvent2));
					addIssue(XBITYPE.Behavior, ISSUETYPE.Additional, issueMsg,
							browserEvent1.getState(), browserEvent1.getImage(),
							browserEvent2.getImage());
					behaviorIssues.add(issueMsg);
				} else if (browserEvent2.getMutation() == null) {
					String issueMsg = formatIssuseString("MISS_MUTATION_2",
							page + "_Event_" + i,
							eventMsgFormat(browserEvent1),
							eventMsgFormat(browserEvent2));
					addIssue(XBITYPE.Behavior, ISSUETYPE.Missing, issueMsg,
							browserEvent1.getState(), browserEvent1.getImage(),
							browserEvent2.getImage());
					behaviorIssues.add(issueMsg);
				} else {
					String eventId = page + "_Event_" + i + "_"
							+ browserEvent1.getType() + "_"
							+ browserEvent1.getPath();
					checkEvent(eventId, browserEvent1, browserEvent2);
				}
			} else {
				String issueMsg = formatIssuseString("MISSMATCH_EVENT_", page
						+ "_Event_" + i, eventMsgFormat(browserEvent1),
						eventMsgFormat(browserEvent2));
				addIssue(XBITYPE.Behavior, ISSUETYPE.Missing, issueMsg,
						browserEvent1, browserEvent2);
				behaviorIssues.add(issueMsg);
			}
			System.out.print("event_" + i + ":");
			System.out.println(new Date().getTime() - startTime);
			System.out.println();
		}

		int j = i;
		for (; j < browserEventList1.size(); j++) {
			BrowserEvent browserEvent1 = browserEventList1.get(j);
			String issueMsg = formatIssuseString("MISS_EVENT_2", page
					+ "_Event_" + j, eventMsgFormat(browserEvent1), "*:*");
			addIssue(XBITYPE.Behavior, ISSUETYPE.Missing, issueMsg,
					browserEvent1.getState(), browserEvent1.getImage(), "");
			behaviorIssues.add(issueMsg);
		}
		j = i;
		for (; j < browserEventList2.size(); j++) {
			BrowserEvent browserEvent2 = browserEventList2.get(j);
			String issueMsg = formatIssuseString("MISS_EVENT_1", page
					+ "_Event_" + j, "*:*", eventMsgFormat(browserEvent2));
			addIssue(XBITYPE.Behavior, ISSUETYPE.Additional, issueMsg,
					browserEvent2.getState(), "", browserEvent2.getImage());
			behaviorIssues.add(issueMsg);
		}
		this.results.addBehaviorIssues(behaviorIssues);
	}

	private void checkEvent(String eventId, BrowserEvent browserEvent1,
			BrowserEvent browserEvent2) {
		List<String> layoutIssues = new ArrayList<String>();
		MutationEvent mutation1 = browserEvent1.getMutation();
		MutationEvent mutation2 = browserEvent2.getMutation();
		String image1 = browserEvent1.getAbsoluteImage();
		String image2 = browserEvent2.getAbsoluteImage();

		Map<String, LocalPage> localMap1 = mutation1.getLocalPageMap();
		Map<String, LocalPage> localMap2 = mutation2.getLocalPageMap();
		long start = new Date().getTime();
		// match remove node
		removeMatch(eventId, mutation1.getRemoveMap(),
				mutation2.getRemoveMap(), browserEvent1.getState(),
				browserEvent1.getImage(), browserEvent2.getImage());
		long end = new Date().getTime();
		System.out.println("remove match:" + (end - start));
		start = end;
		// match added node
		addMatch(eventId, mutation1.getAdded(), mutation2.getAddMap(),
				mutation2.getIdMap(), browserEvent1.getState(),
				browserEvent1.getImage(), browserEvent2.getImage());
		end = new Date().getTime();
		System.out.println("add match:" + (end - start));
		if ((localMap1 == null || localMap1.isEmpty())
				&& (localMap2 == null || localMap2.isEmpty())) {
			return;
		} else if (localMap1 == null || localMap1.isEmpty()) {
//			String issueMsg = formatIssuseString("MISS_PART_1", eventId, "*",
//					eventId);
//			addIssue(XBITYPE.Layout, ISSUETYPE.Additional, issueMsg,
//					browserEvent1.getState(), browserEvent1.getImage(),
//					browserEvent2.getImage());
//			layoutIssues.add(issueMsg);
			return;
		} else if (localMap2 == null || localMap2.isEmpty()) {
//			String issueMsg = formatIssuseString("MISS_PART_2", eventId,
//					eventId, "*");
//			addIssue(XBITYPE.Layout, ISSUETYPE.Missing, issueMsg,
//					browserEvent1.getState(), browserEvent1.getImage(),
//					browserEvent2.getImage());
//			layoutIssues.add(issueMsg);
			return;
		}
		// create image handler
		IMGHandler imgHandler = null;
		if (!isTest) {
			if (image1 != null && image2 != null) {
				try {
					imgHandler = new IMGHandler(image1, image2,
							browserPage1.getHash(), browserPage2.getHash());
				} catch (Exception e) {
					e.printStackTrace();
				}
			} else if (image1 == null ^ image2 == null) {
				String issueMsg = formatIssuseString("MISS_IMAGE", eventId,
						image1, image2);
				addIssue(XBITYPE.Layout, ISSUETYPE.Missing, issueMsg,
						browserEvent1.getState(), browserEvent1.getImage(),
						browserEvent2.getImage());
				layoutIssues.add(issueMsg);
			}
		}
		// do match part
		Map<String, LocalPage> id1Page2 = matchPart(localMap1, localMap2);
		for (String rootId1 : localMap1.keySet()) {
			// local page match
			LocalPage localPage1 = localMap1.get(rootId1);
			LocalPage localPage2 = id1Page2.get(rootId1);
			if (localPage2 != null) {
				checkPart(eventId, localPage1, localPage2, imgHandler,
						browserEvent1.getState(), browserEvent1.getImage(),
						browserEvent2.getImage());
				;
				localMap2.remove(localPage2.getLocalRoot().getNodeid());
			} else {
				String issueMsg = formatIssuseString("MISSMATCH_PART_2",
						eventId, formatNodeInfo(localPage1.getLocalRoot()), "*");
				XbiIssue xbiIssue = addIssue(XBITYPE.Layout, ISSUETYPE.Missing,
						issueMsg, browserEvent1.getState(),
						browserEvent1.getImage(), browserEvent2.getImage());
				xbiIssue.setRefNode(localPage1.getLocalRoot());
				layoutIssues.add(issueMsg);
			}
		}
		for (String rootId2 : localMap2.keySet()) {
			String issueMsg = formatIssuseString("MISSMATCH_PART_1", eventId,
					"*", formatNodeInfo(localMap2.get(rootId2).getLocalRoot()));
			XbiIssue xbiIssue = addIssue(XBITYPE.Layout, ISSUETYPE.Missing,
					issueMsg, browserEvent1.getState(),
					browserEvent1.getImage(), browserEvent2.getImage());
			xbiIssue.setCmpNode(localMap2.get(rootId2).getLocalRoot());
			layoutIssues.add(issueMsg);
		}
		if (imgHandler != null)
			imgHandler.finish();
		results.addLayoutIssues(stateKey, layoutIssues);
	}

	private Map<String, LocalPage> matchPart(Map<String, LocalPage> localMap1,
			Map<String, LocalPage> localMap2) {
		Map<String, LocalPage> match = new HashMap<>();
		for (String root1 : localMap1.keySet()) {
			String root1_m = allMatchedNode.get(root1);
			LocalPage localPage2 = localMap2.get(root1_m);
			if (localPage2 == null) {
				// Do match
				String nodeXpath1 = localMap1.get(root1).getLocalRoot()
						.getxPath();
				LocalPage bestMatch = null;
				float matchIdx = 0;
				for (String root2 : localMap2.keySet()) {
					localPage2 = localMap2.get(root2);
					DomNode node2 = localPage2.getLocalRoot();
					String nodeXpath2 = node2.getxPath();
					float dis = 1
							- StringUtils.getLevenshteinDistance(nodeXpath1,
									nodeXpath2)
							/ (float) Math.max(nodeXpath1.length(),
									nodeXpath2.length());
					if (dis > matchIdx) {
						bestMatch = localPage2;
						matchIdx = dis;
					}
				}
				if (bestMatch != null) {
					match.put(root1, bestMatch);
				}
			} else {
				match.put(root1, localPage2);
			}
		}
		return match;
	}

	private void checkPart(String eventId, LocalPage localPage1,
			LocalPage localPage2, IMGHandler imgHandler, int state,
			String image1, String image2) {
		// build ag
		long start = new Date().getTime();
		AlignmentGraph ag1 = new AlignmentGraph(localPage1.getLocalRoot());
		AlignmentGraph ag2 = new AlignmentGraph(localPage2.getLocalRoot());
		long end = new Date().getTime();
		System.out.println("build ag:" + (end - start));
		// compare
		compareAGD(eventId, ag1, localPage1.getChangedNode(), ag2,
				localPage2.getChangedNode(), imgHandler, state, image1, image2);
	}

	private void removeMatch(String eventId, Map<String, DomNode> removeMap1,
			Map<String, DomNode> removeMap2, int state, String image1,
			String image2) {
		List<String> layoutIssues = new ArrayList<>();
		if ((removeMap1 == null || removeMap1.isEmpty())
				&& (removeMap2 == null || removeMap2.isEmpty())) {
			return;
		} else if (removeMap1 == null || removeMap1.isEmpty()) {
			String issueMsg = formatIssuseString("MISS_REMOVE_NODE_1", eventId,
					"*", eventId);
			addIssue(XBITYPE.Layout, ISSUETYPE.Additional, issueMsg, state,
					image1, image2);
			layoutIssues.add(issueMsg);
			return;
		} else if (removeMap2 == null || removeMap2.isEmpty()) {
			String issueMsg = formatIssuseString("MISS_REMOVE_NODE_2", eventId,
					eventId, "*");
			addIssue(XBITYPE.Layout, ISSUETYPE.Missing, issueMsg, state,
					image1, image2);
			layoutIssues.add(issueMsg);
			return;
		}
		Iterator<Map.Entry<String, DomNode>> it = removeMap1.entrySet()
				.iterator();
		while (it.hasNext()) {
			Map.Entry<String, DomNode> remove1 = it.next();
			String removeKey2 = allMatchedNode.get(remove1.getKey());
			if (removeKey2 != null) {
				if (removeMap2.containsKey(removeKey2)) {
					removeMap2.remove(removeKey2);
				} else {
					// doesn't match
					if (!LayoutUtils.isLayoutNode(remove1.getValue()))
						continue;
					String issueMsg = formatIssuseString("MISSMATCH_NODE_2",
							eventId + "_removed",
							formatNodeInfo(remove1.getValue()), "*");
					XbiIssue xbiIssue = addIssue(XBITYPE.Layout,
							ISSUETYPE.Missing, issueMsg, state, image1, image2);
					xbiIssue.setRefNode(remove1.getValue());
					layoutIssues.add(issueMsg);
				}
			}
			allMatchedNode.remove(remove1.getKey());
		}
		// collect ummatch node
		for (DomNode remove2 : removeMap2.values()) {
			if (!LayoutUtils.isLayoutNode(remove2))
				continue;
			String issueMsg = formatIssuseString("MISSMATCH_NODE_1", eventId
					+ "_removed", formatNodeInfo(remove2), "*");
			XbiIssue xbiIssue = addIssue(XBITYPE.Layout, ISSUETYPE.Additional,
					issueMsg, state, image1, image2);
			xbiIssue.setCmpNode(remove2);
			layoutIssues.add(issueMsg);
		}
		results.addLayoutIssues(stateKey, layoutIssues);
	}

	private void addMatch(String eventId, List<DomNode> addList1,
			Map<String, DomNode> addMap2, Map<String, DomNode> idMap2,
			int state, String image1, String image2) {
		List<String> behaviorIssues = new ArrayList<String>();
		if ((addList1 == null || addList1.isEmpty())
				&& (addMap2 == null || addMap2.isEmpty())) {
			return;
		} else if (addList1 == null || addList1.isEmpty()) {
			String issueMsg = formatIssuseString("NO_ADD_NODE_1", eventId, "*",
					eventId);
			addIssue(XBITYPE.Behavior, ISSUETYPE.Additional, issueMsg, state,
					image1, image2);
			behaviorIssues.add(issueMsg);
		} else if (addMap2 == null || addMap2.isEmpty()) {
			String issueMsg = formatIssuseString("NO_ADD_NODE_2", eventId,
					eventId, "*");
			addIssue(XBITYPE.Behavior, ISSUETYPE.Missing, issueMsg, state,
					image1, image2);
			behaviorIssues.add(issueMsg);
		} else {
			Matcher domMatcher = new Matcher(allMatchedNode);
			MatchResult mr = domMatcher.doMatch(addList1, addMap2, idMap2);
			List<DomNode> unMatched1 = mr.getUnmatched1();
			List<DomNode> unMatched2 = mr.getUnmatched2();
			HashSet<String> layoutIssues = new HashSet<String>();
			for (DomNode domNode : unMatched1) {
				if (!LayoutUtils.isLayoutNode(domNode))
					continue;
				String issueMsg = formatIssuseString("MISSMATCH_NODE_2",
						eventId, formatNodeInfo(domNode), "*");
				XbiIssue xbiIssue = addIssue(XBITYPE.Layout, ISSUETYPE.Missing,
						issueMsg, state, image1, image2);
				xbiIssue.setRefNode(domNode);
				layoutIssues.add(issueMsg);
			}
			for (DomNode domNode : unMatched2) {
				if (!LayoutUtils.isLayoutNode(domNode))
					continue;
				String issueMsg = formatIssuseString("MISSMATCH_NODE_1",
						eventId, "*", formatNodeInfo(domNode));
				XbiIssue xbiIssue = addIssue(XBITYPE.Layout,
						ISSUETYPE.Additional, issueMsg, state, image1, image2);
				xbiIssue.setCmpNode(domNode);
				layoutIssues.add(issueMsg);
			}
			results.addLayoutIssues(stateKey, new ArrayList<String>(
					layoutIssues));
		}
		results.addBehaviorIssues(behaviorIssues);
	}

	private void compareAGD(String eventId, AlignmentGraph ag1,
			List<DomNode> changedList1, AlignmentGraph ag2,
			List<DomNode> changedList2, IMGHandler imgHandler, int state,
			String image1, String image2) {
		long start = new Date().getTime();
		LinkedHashSet<String> layoutIssues = new LinkedHashSet<String>();
		// int preIdx = this.results.getLayoutIssues().get(stateKey).size();

		long end = new Date().getTime();
		start = end;
		StateIssue stateIssue = results.getStateIssues().get(state);
		if (stateIssue == null) {
			stateIssue = new StateIssue(state, image1, image2);
		}
		AGDiff agDiffer = new AGDiff(eventId, allMatchedNode, ag1, ag2,
				stateIssue);
		
		List<DomNode> workList = new ArrayList<>();
		workList.addAll(changedList1);
		List<DomNode> textNodeList = new ArrayList<>();
		Map<String, DomNode> textNodeMap2 = new HashMap<>();
		end = new Date().getTime();
		start = end;
		// compare parent
		Iterator<DomNode> it = workList.iterator();
		while (it.hasNext()) {
			DomNode domNode = it.next();
			if (domNode.isText()) {
				textNodeList.add(domNode);
				it.remove();
				continue;
			}

			AGNode a = ag1.getvMap().get(domNode.getHash());
			if (a == null) {
				// a isn't a layout node
				it.remove();
				continue;
			}
			AGNode b = ag2.getvMap().get(allMatchedNode.get(domNode.getHash()));
			if (b == null) {
				String issueMsg = formatIssuseString("MISSMATCH_NODE_2",
						eventId, formatNodeInfo(a.getDomNode()), "*");
				if (layoutIssues.add(issueMsg) && imgHandler != null) {
					XbiIssue xbiIssue = addIssue(XBITYPE.Layout,
							ISSUETYPE.Missing, issueMsg, state, image1, image2);
					xbiIssue.setRefNode(domNode);
					imgHandler.setRectInImage(a, null);
				}
				it.remove();
				continue;
			}
			HashSet<String> issues = agDiffer.diffParent(a.getHash(),
					b.getHash());
			if (!issues.isEmpty()) {
				if (layoutIssues.addAll(issues) && imgHandler != null) {
					imgHandler.setRectInImage(a, b);
					imgHandler.setRectInImage(a.getParent(), b.getParent());
					// imgHandler.setRectInImage(
					// layoutIssueSize + layoutIssues.size() + 1, a.getParent(),
					// b.getParent());
				}
			}
		}
		end = new Date().getTime();
		start = end;
		// compare sibling
		for (DomNode domNode : workList) {
			AGNode a = ag1.getvMap().get(domNode.getHash());
			AGNode b = ag2.getvMap().get(allMatchedNode.get(a.getHash()));
			if (b == null)
				continue;
			HashSet<String> issues = agDiffer.diffSibling(a.getHash(),
					b.getHash());
			if (issues != null) {
				if (issues.isEmpty() && imgHandler != null) {
					// compare screenshot
					if (imgHandler.diffNodeImg(a, b)) {
						String issueMsg = formatIssuseString("IMG_DIFF",
								eventId, formatNodeInfo(a.getDomNode()),
								formatNodeInfo(b.getDomNode()));
						XbiIssue xbiIssue = addIssue(XBITYPE.Layout,
								ISSUETYPE.Different, issueMsg, state, image1,
								image2);
						xbiIssue.setRefNode(a.getDomNode());
						xbiIssue.setCmpNode(b.getDomNode());
						layoutIssues.add(issueMsg);
						imgHandler.setRectInImage(a, b);
					}
				} else {
					// only paint the last issues for the same node
					if (layoutIssues.addAll(issues) && imgHandler != null) {
						imgHandler.setRectInImage(a, b);
					}
				}
			}
			// clear match node in change list 2
			changedList2.remove(b.getDomNode());// 待测
		}
		end = new Date().getTime();
		start = end;
		if (!isTest) {
			// collect text node from change list 2
			for (DomNode domNode : changedList2) {
				if (domNode.isText()) {
					textNodeMap2.put(domNode.getHash(), domNode);
				}
				/*
				 * else{ if(ag2.getvMap().get(domNode.getHash()) != null){
				 * if(!LayoutUtils.isLayoutNode(domNode)) continue;
				 * layoutIssues.add(formatIssuseString("MISSMATCH_NODE_1",
				 * eventId, "*", formatNodeInfo(domNode))); } }
				 */
			}
			end = new Date().getTime();
			start = end;
			// compare text
			for (DomNode a : textNodeList) {
				AGNode parentA = ag1.getvMap().get(a.getPid());
				if (parentA == null)
					continue;
				DomNode b = textNodeMap2.get(allMatchedNode.get(a.getHash()));
				if (b == null) {
					String issueMsg = formatIssuseString(
							"MISSMATCH_TEXTNODE_2", eventId, formatNodeInfo(a),
							"*");
					if (layoutIssues.add(issueMsg) && imgHandler != null) {
						XbiIssue xbiIssue = addIssue(XBITYPE.Layout,
								ISSUETYPE.Missing, issueMsg, state, image1,
								image2);
						xbiIssue.setRefNode(a);
						imgHandler.setRectInImage(parentA, null);
					}
					continue;
				}
				if (!StringUtils.equals(a.getText(), b.getText())) {
					String issueMsg = formatIssuseString("TEXT_DIFF", eventId,
							formatNodeInfo(a), formatNodeInfo(b));
					if (layoutIssues.add(issueMsg) && imgHandler != null) {
						XbiIssue xbiIssue = addIssue(XBITYPE.Layout,
								ISSUETYPE.Different, issueMsg, state, image1,
								image2);
						xbiIssue.setRefNode(a);
						xbiIssue.setCmpNode(b);

						AGNode parentB = ag2.getvMap().get(b.getPid());
						imgHandler.setRectInImage(parentA, parentB);
					}
				}
			}
			end = new Date().getTime();
			start = end;
		}
		if (stateIssue.getIssueList().size() != 0) {
			results.getStateIssues().put(state, stateIssue);
		}
		this.results.addLayoutIssues(stateKey, new ArrayList<String>(
				layoutIssues));
		System.out.print("compareAGD:");
		System.out.println(new Date().getTime() - start);
	}

	private String eventMsgFormat(BrowserEvent browserEvent) {
		return browserEvent.getType() + ":" + browserEvent.getPath();
	}
	
	private boolean equalEventByState(BrowserEvent browserEvent1,
			BrowserEvent browserEvent2) {
		return true;
//		if(browserEvent1.getType().equals("setTimeout") && browserEvent2.getType().equals("setTimeout")){
//			browserEvent1.setState(stateCount);
//			browserEvent2.setState(stateCount);
//			stateCount--;
//			return true;
//		}
//		return browserEvent1.getState() != -1 && browserEvent1.getState() == browserEvent2
//						.getState();
	}
	private static int count = Integer.MAX_VALUE;
	private boolean equalEvent(BrowserEvent browserEvent1,
			BrowserEvent browserEvent2) {
		browserEvent1.setState(count);
		browserEvent2.setState(count);
		count--;
		return browserEvent1.getType() != null
				&& browserEvent1.getType().equals(browserEvent2.getType())
				&& ((browserEvent1.getPath() == null && browserEvent2.getPath() == null) || (browserEvent1
						.getPath() != null && browserEvent1.getPath().equals(
						browserEvent2.getPath())));
	}

	private String formatNodeInfo(DomNode node) {
		if (node == null)
			return "";
		if (node.getNodeType() == 0) {
			String text = node.getText();
			String nTextString = text == null ? "" : text.replace("\n", "\\n")
					.replace("\r", "\\r").replace("\t", "\\t");
			return "Text:" + node.getxPath() + ":" + nTextString;
		} else {
			return node.getId() + ":" + node.getxPath();
		}
	}

	private String formatIssuseString(String msg, String eventId, String node1,
			String node2) {
		return String.format("\"%s\",\"%s\",\"%s\",\"%s\"", msg, eventId,
				node1, node2);
	}

	private XbiIssue addIssue(XBITYPE type, ISSUETYPE issue, String msg,
			List<BrowserEvent> eventList1, List<BrowserEvent> eventList2) {
		return addIssue(type, issue, msg, getLoadEvent(eventList1),
				getLoadEvent(eventList2));
	}

	private XbiIssue addIssue(XBITYPE type, ISSUETYPE issue, String msg,
			BrowserEvent event1, BrowserEvent event2) {
		int state = -1;
		String refImage = "", testImage = "";
		if (event2 != null) {
			state = event2.getState();
			testImage = event2.getImage();
		}
		if (event1 != null) {
			state = event1.getState();
			refImage = event1.getImage();
		}
		return addIssue(type, issue, msg, state, refImage, testImage);
	}

	private BrowserEvent getLoadEvent(List<BrowserEvent> eventList) {
		if (eventList == null)
			return null;
		for (BrowserEvent event : eventList) {
			if (event.getType().equals("load")) {
				return event;
			}
		}
		return null;
	}

	private XbiIssue addIssue(XBITYPE type, ISSUETYPE issue, String msg,
			int state, String refImage, String testImage) {
		StateIssue stateIssue = results.getStateIssues().get(state);
		if (stateIssue == null) {
			stateIssue = new StateIssue(state, refImage, testImage);
			results.getStateIssues().put(state, stateIssue);
		}
		XbiIssue xbiIssue = new XbiIssue(type, issue, msg);
		stateIssue.addIssue(xbiIssue);
		return xbiIssue;
	}
}
